package io.gitee.kotle.player.core.impl

import android.os.SystemClock
import io.gitee.kotle.player.core.IPlayer
import io.gitee.kotle.player.core.currentIndex
import io.gitee.kotle.player.core.isFirstIndex
import io.gitee.kotle.player.core.isLastIndex
import io.gitee.kotle.player.download.IPlayerDownload
import kotlinx.coroutines.*

/**
 *
 * 描述：基类播放器，做一些统一处理
 *
 * @author Jiale.Wei
 *
 * 创建时间：2023/4/12 15:52
 *
 */
abstract class BasePlayer<Media, Model : IPlayer.IModel<Media>> : IPlayer<Media, Model> {
    /**
     * 默认创建在主线程的协程作用域
     */
    private val _scope by lazy { MainScope() }
    override val scope: CoroutineScope
        get() = _scope

    /**
     * 下载器
     */
    private var _downloader: IPlayerDownload<Media>? = null
    override var downloader: IPlayerDownload<Media>?
        get() = _downloader
        set(value) {
            _downloader = value
        }

    /**
     * 播放模式
     */
    private var _repeatMode: IPlayer.RepeatMode = IPlayer.RepeatMode.Off
    override var repeatMode: IPlayer.RepeatMode
        get() = _repeatMode
        set(value) {
            _repeatMode = value
            doListener { player, listener ->
                listener.onRepeatMode(player, _repeatMode)
            }
        }

    /**
     * 监听器
     */
    private val _listener = mutableListOf<IPlayer.IListener<Media, Model>>()
    override val listeners: List<IPlayer.IListener<Media, Model>>
        get() = _listener

    private var _currentModel: Model? = null
    override val currentModel: Model
        get() = _currentModel ?: throw IllegalArgumentException("no playing model")

    private var _currentModelState: IPlayer.ModelState? = null
    override val currentModelState: IPlayer.ModelState
        get() = _currentModelState ?: IPlayer.ModelState.Stop

    override val hasModel: Boolean
        get() = _currentModel != null

    /**
     * 设置数据模型
     */
    private var _models: MutableList<Model> = mutableListOf()
    override var models: MutableList<Model>
        get() = _models
        set(value) {
            val old = _models ?: mutableListOf()
            _models = value
            doListener { player, listener ->
                listener.onModelsChange(player, old, value)
            }
        }

    /**
     * 定时器的时间间隔
     */
    private var _tickIntervalMillis = 1000L
    override var tickIntervalMillis: Long
        get() = _tickIntervalMillis
        set(value) {
            _tickIntervalMillis = value
        }

    /**
     * 准备资源
     */
    private var prepareJob: Job? = null
    override fun prepare(index: Int) {
        stop()
        val oldModel = _currentModel
        _currentModel = models.getOrNull(index)
        if (!hasModel) {
            return
        }
        val newModel = currentModel
        prepareJob = scope.launch {
            doListener { player, listener ->
                oldModel?.onModelDetachedFromPlayer(this, player)
                listener.onModelChange(this, player, oldModel, newModel)
                newModel.onModelAttachedToPlayer(this, player)
                listener.onPrepareModel(this, player, newModel)
                listener.onTick(this, player)
            }
            try {
                updateModelState(IPlayer.ModelState.Prepare)
                onStartPrepare(this, this@BasePlayer, newModel)
                //触发回调，可以保证及时更新
                doListener { player, listener ->
                    listener.onTick(this, player)
                }
            } catch (error: Throwable) {
                updateModelState(IPlayer.ModelState.Error)
                doListener { player, listener ->
                    listener.onError(player, error)
                }
            }
        }
    }

    override fun stop() {
        if (prepareJob?.isActive == true) {
            prepareJob?.cancel()
        }
    }

    override fun next() {
        if (hasModel) {
            when (repeatMode) {
                IPlayer.RepeatMode.All -> {
                    if (isLastIndex) {
                        prepare(0)
                    } else {
                        prepare(currentIndex + 1)
                    }
                }

                IPlayer.RepeatMode.Off -> {
                    if (!isLastIndex) {
                        prepare(currentIndex + 1)
                    }
                }

                IPlayer.RepeatMode.One -> {
                    currentPosition = 0
                }

                IPlayer.RepeatMode.Shuffle -> {
                    val rangeIndex = IntRange(0, models.count()).random()
                    if (rangeIndex == currentIndex) {
                        currentPosition = 0
                    } else {
                        prepare(rangeIndex)
                    }
                }
            }
        }
    }

    override fun previous() {
        if (hasModel) {
            when (repeatMode) {
                IPlayer.RepeatMode.All -> {
                    if (isFirstIndex) {
                        prepare(models.lastIndex)
                    } else {
                        prepare(currentIndex - 1)
                    }
                }

                IPlayer.RepeatMode.Off -> {
                    if (!isFirstIndex) {
                        prepare(currentIndex - 1)
                    }
                }

                IPlayer.RepeatMode.One -> {
                    currentPosition = 0
                }

                IPlayer.RepeatMode.Shuffle -> {
                    val rangeIndex = IntRange(0, models.count()).random()
                    if (rangeIndex == currentIndex) {
                        currentPosition = 0
                    } else {
                        prepare(rangeIndex)
                    }
                }
            }
        }
    }

    abstract suspend fun onStartPrepare(
        scope: CoroutineScope,
        player: IPlayer<Media, Model>,
        model: Model
    )

    /**
     * 添加监听
     */
    override fun addListener(listener: IPlayer.IListener<Media, Model>?) {
        if (listener != null && !_listener.contains(listener)) {
            _listener.add(listener)
            listener.onAttached(this)
        }
    }

    /**
     * 移除监听
     */
    override fun removeListener(listener: IPlayer.IListener<Media, Model>?) {
        if (listener != null && _listener.contains(listener)) {
            listener.onDetached(this)
            _listener.remove(listener)
        }
    }

    /**
     * 监听器内联
     */
    inline fun doListener(action: (player: IPlayer<Media, Model>, listener: IPlayer.IListener<Media, Model>) -> Unit) {
        listeners.toList().forEach {
            action.invoke(this, it)
        }
    }

    /**
     * 开始定时器
     */
    private var _tickJob: Job? = null
    override fun startTick() {
        if (_tickJob?.isActive == true) {
            return
        }
        _tickJob = scope.launch {
            while (isActive) {
                val startTime = SystemClock.elapsedRealtime()
                doListener { player, listener ->
                    listener.onTick(this, player)
                }
                val customMillis = SystemClock.elapsedRealtime() - startTime
                val leftMills = tickIntervalMillis - customMillis
                if (leftMills > 0) {
                    delay(leftMills)
                }
            }
        }
    }

    /**
     * 更新状态
     */
    open fun updateModelState(state: IPlayer.ModelState) {
        if (_currentModelState != state) {
            _currentModelState = state
            doListener { player, listener ->
                listener.onModelState(player, state)
            }
            if (state == IPlayer.ModelState.End) {
                next()
            }
        }
    }

    /**
     * 停止计时器
     */
    override fun stopTick() {
        if (_tickJob?.isActive == true) {
            _tickJob?.cancel()
            _tickJob = null
        }
    }

    final override fun release() {
        //回调资源释放
        scope.launch {
            //停止播放
            stop()
            //停止计时器
            stopTick()
            //回调数据
            _currentModel?.onModelDetachedFromPlayer(this, this@BasePlayer)
            //释放监听器
            _listener.clear()
            //释放models
            _models.clear()
            //下载器释放
            downloader = null
            //子类释放资源
            onRelease(this)
            //取消协程
            scope.cancel("player released")
        }
    }

    open suspend fun onRelease(scope: CoroutineScope) {

    }
}